package com.hbnu.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

/**
 * @author kittychen
 * @since 2025-10-14 17:17
 */
public class ReflectTest {

    public static void main(String[] args) throws Exception {
        // 1、获取字节码对象
        // 1.1、通过类名获取字节码对象
        Class<Person> personClass = Person.class;

        // 1.2、通过具体对象获取字节码对象
        Person person = new Person();
        Class<? extends Person> personClass1 = person.getClass();

        // 1.3、通过Class类中的forName方法获取字节码对象
        Class<?> aClass = Class.forName("com.hbnu.reflect.Person");

        // 2、获取构造方法
        System.out.println("===========================2.获取构造方法===========================");
        // 2.1、获取所有公共构造方法
        System.out.println("获取所有公共构造方法");
        Constructor<?>[] constructors = aClass.getConstructors();  // 获取所有公共构造方法
        System.out.println("获取所有公共构造方法的个数：" + constructors.length);
        for (Constructor<?> constructor : constructors) {
            System.out.print(constructor.getName() + "\t");  // 获取构造方法名称
            Parameter[] parameters = constructor.getParameters();  // 获取构造方法参数
            System.out.print("构造方法参数个数：" + constructor.getParameterCount() + "\t参数名称：");
            for (Parameter parameter : parameters) {
                System.out.print("参数类型：" + parameter.getType() + "\t");
                System.out.print(parameter.getName() + "\t");  // 获取参数名称
            }
            System.out.println();
        }

        // 2.2、获取所有的构造方法，包括私有的
        System.out.println("获取所有的构造方法，包括私有的");
        Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors();
        System.out.println("获取所有的构造方法，包括私有的个数：" + declaredConstructors.length);
        for (Constructor<?> constructor : declaredConstructors) {
            System.out.print(constructor.getName() + "\t");  // 获取构造方法名称
            Parameter[] parameters = constructor.getParameters();  // 获取构造方法参数
            System.out.print("构造方法参数个数：" + constructor.getParameterCount() + "\t参数名称：");
            for (Parameter parameter : parameters) {
                System.out.print("参数类型：" + parameter.getType() + "\t");
                System.out.print(parameter.getName() + "\t");  // 获取参数名称
            }
            System.out.println();
        }

        // 2.3、获取指定的构造方法
        System.out.println("获取指定的构造方法");
        Constructor<?> constructor = aClass.getConstructor(String.class, int.class);
        // 通过反射获取指定构造器，并创建实例对象
        Person person1 = (Person) constructor.newInstance("张三", 18);
        System.out.println("通过反射创建的对象：" + person1.getName());

        Person person2 = (Person) aClass.newInstance();
        // 3、获取属性成员
        System.out.println("===========================3.获取属性成员===========================");
        // 3.1、获取所有公共属性成员
        Field[] fields = aClass.getFields();  // 获取所有公共属性成员
        System.out.println("获取所有公共属性成员的个数：" + fields.length);
        for (Field field : fields) {
            System.out.print("成员类型：" + field.getType().getName() + "\t成员名称：");  // 获取属性成员类型
            System.out.println(field.getName());  // 获取属性成员名称
        }
        // 3.2、获取所有属性成员
        Field[] declaredFields = aClass.getDeclaredFields();  // 获取所有公共属性成员
        System.out.println("获取所有属性成员的个数：" + declaredFields.length);
        for (Field field : declaredFields) {
            System.out.print("成员类型：" + field.getType().getName() + "\t成员名称：");  // 获取属性成员类型
            System.out.println(field.getName());  // 获取属性成员名称
        }
        // 3.3、给指定的公共成员属性赋值
        Field addressFiled = aClass.getField("address");
        addressFiled.set(person2, "北京");
        System.out.println("通过反射给公共属性" + addressFiled.getName() + "赋值：" + person2.getAddress());
        // 3.4、给指定的私有成员属性赋值
        Field ageFiled = aClass.getDeclaredField("age");
        ageFiled.setAccessible(true);
        ageFiled.set(person2, 20);
        System.out.println("通过反射给私有属性" + ageFiled.getName() + "赋值：" + person2.getAge());

        // 3、获取成员方法
        System.out.println("===========================4.获取成员方法===========================");
        Method[] methods = aClass.getMethods();  // 获取所有公共成员方法（包括继承过来的方法）
        System.out.println("获取所有公共成员方法的个数：" + methods.length);
        for (Method method : methods) {
            System.out.println("方法返回值：" + method.getReturnType().getName() + "\t方法名称：" + method.getName());
            Parameter[] parameters = method.getParameters();  // 获取方法参数
            System.out.print("方法参数个数：" + method.getParameterCount() + "\t参数名称：");
            for (Parameter parameter : parameters) {
                System.out.println(parameter.getName() + "参数类型：" + parameter.getType() + "\t");
            }
        }
        System.out.println();
        System.out.println("------------------------所有成员方法的个数（不包括继承过来的方法）-------------------------");
        Method[] declaredMethods = aClass.getDeclaredMethods();   // 获取所有成员方法(不包括继承过来的方法)
        System.out.println("所有成员方法的个数（不包括继承过来的方法）：" + declaredMethods.length);
        for (Method method : declaredMethods) {
            System.out.println("方法返回值：" + method.getReturnType().getName() + "\t方法名称：" + method.getName());
            Parameter[] parameters = method.getParameters();  // 获取方法参数
            System.out.print("方法参数个数：" + method.getParameterCount() + "\t参数名称：");
            for (Parameter parameter : parameters) {
                System.out.println(parameter.getName() + "参数类型：" + parameter.getType() + "\t");
            }
        }
        System.out.println("------------------获取指定的公共方法--------------------");
        Method method = aClass.getMethod("method1");
        method.invoke(person2);
        System.out.println("------------------获取指定的私有方法--------------------");
        Method method2 = aClass.getDeclaredMethod("method2", String.class);
        method2.setAccessible(true);
        String result = (String) method2.invoke(person2, "kittychen");
        System.out.println(result);
    }
}
